﻿#if !Profile && MVCCTQ
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Transactions;
using O1.Kernel;
using O1.Kernel.Primitives;
using O1.Kernel.Storage;
using O1.Kernel.Storage.Transactions;

namespace O1.Profiling
{
    class Program
    {
        private const int size = 1024 * 1024;

        private static readonly Tx[] sampleHeaders = new Tx[] 
            {
                new Tx(((ulong)1).EmbedStatus(TxStatus.Committed), ulong.MaxValue),
                new Tx(((ulong)2).EmbedStatus(TxStatus.Committed), ulong.MaxValue),
                new Tx(((ulong)3).EmbedStatus(TxStatus.Committed), ulong.MaxValue),
                new Tx((ulong)5, ulong.MaxValue),
                new Tx((ulong)6, ulong.MaxValue),
            };

        private static readonly byte[][] cells = BuildTestCells(123, sampleHeaders);

        private static readonly byte[] newCell = BuildTestCell(123, new Tx((ulong)7, ulong.MaxValue));

        static void Main(string[] args)
        {
            var bytesAllocated = GC.GetTotalMemory(true);
            var stopwatch = Stopwatch.StartNew();

            var sequence = new StorageSequence();
            var storage = new MultiVersionBinaryStorage(size, sequence);

            stopwatch.Stop();
            Console.WriteLine("");
            var difference = GC.GetTotalMemory(true) - bytesAllocated;
            Console.WriteLine("Allocated " + size + " MVCC storage.");
            Console.WriteLine("...in " + stopwatch.ElapsedMilliseconds + " milliseconds.");

            stopwatch.Restart();
            for (int i = 0; i < size; i++)
            {
                ulong txId = (ulong)((i % 7) + 8);
                storage.Write(sequence.NextId(), newCell, new ConcurrencyToken(txId, (ulong)((i % 7) + 5)));
            }

            for (int i = 0; i < size; i++)
            {
                ulong txId = (ulong)((i % 7) + 8);
                var token = new ConcurrencyToken(txId, (ulong)((i % 7) + 5));
                var data = storage.Read((uint)i, token);
                storage.Write((uint)i, newCell, token);
            }

            while (storage.HasPendingWrites) ;

            stopwatch.Stop();
            Console.WriteLine("Processed " + size + " cells in " + stopwatch.ElapsedMilliseconds + " milliseconds.");
            Console.WriteLine("... " + stopwatch.ElapsedMilliseconds / size + " milliseconds per cell.");
            Console.ReadLine();
        }

        private static byte[][] BuildTestCells(uint cellId, Tx[] headers)
        {
            var result = new byte[headers.Length][];
            for (int i = 0; i < headers.Length; ++i)
            {
                result[i] = BuildTestCell(cellId, headers[i]);
            }

            return result;
        }

        private static byte[] BuildTestCell(uint cellId, Tx header)
        {
            var cellHead = new VertexHead(header, new CellAddress(0, cellId));
            var result = new byte[VertexHead.Size];
            cellHead.Write(result, 0);
            return result;
        }
    }
}
#endif